package com.pencilisland.pay.core.service.impl;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.pencilisland.pay.api.bean.constant.GoodsConstant;
import com.pencilisland.pay.api.bean.constant.OrderConstant;
import com.pencilisland.pay.api.bean.mp.app.WxPayUnifyOrderREQ;
import com.pencilisland.pay.api.bean.mp.app.WxPayUnifyOrderRES;
import com.pencilisland.pay.api.bean.mp.mgt.SyncOrderREQ;
import com.pencilisland.pay.api.bean.mp.mgt.SyncOrderRES;
import com.pencilisland.pay.api.bean.wxpay.WxpayOrderReq;
import com.pencilisland.pay.api.bean.wxpay.WxpaySubmitReq;
import com.pencilisland.pay.api.config.AppConfig;
import com.pencilisland.pay.api.entity.GoodsEntity;
import com.pencilisland.pay.api.entity.OrderAddressEntity;
import com.pencilisland.pay.api.entity.TradeOrderEntity;
import com.pencilisland.pay.api.entity.UserAddressEntity;
import com.pencilisland.pay.api.repository.GoodsRepository;
import com.pencilisland.pay.api.repository.OrderAddressRepository;
import com.pencilisland.pay.api.repository.TradeOrderRepository;
import com.pencilisland.pay.api.repository.UserAddressRepository;
import com.pencilisland.pay.api.service.CacheService;
import com.pencilisland.pay.api.service.WxpayService;
import com.pencilisland.pay.api.util.G;
import com.pencilisland.pay.api.util.RandomUtil;
import com.pencilisland.pay.core.service.CoreAppService;
import com.pencilisland.pay.core.service.RestService;

@Component
public class CoreAppServiceImpl implements CoreAppService {

	Logger log = LoggerFactory.getLogger(getClass());

	private Lock lock = new ReentrantLock();

	@Autowired
	GoodsRepository goodsRepo;
	@Autowired
	CacheService cacheService;
	@Autowired
	AppConfig appConfig;
	@Autowired
	WxpayService wxpayService;
	@Autowired
	TradeOrderRepository tradeOrderRepo;
	@Autowired
	OrderAddressRepository orderAddressRepo;
	@Autowired
	RestService restService;
	@Autowired
	UserAddressRepository userAddressRepo;

	@Override
	public WxPayUnifyOrderRES wxPayUnifyOrder(WxPayUnifyOrderREQ req) {
		log.info("微信支付统一下单处理【{}】【{}】", req.getGoodsCode(), req.getBuyNum());

		GoodsEntity goodsE = cacheService.retrieveGoods(req.getGoodsCode());
		if (goodsE == null) {
			return new WxPayUnifyOrderRES(false, null, "购买商品不存在");
		}
		
		if(goodsE.getStatus()==GoodsConstant.STATUS_0){
			return new WxPayUnifyOrderRES(false, null, "购买商品未开通购买");
		}


		TradeOrderEntity tradeOrder = new TradeOrderEntity();
		
		lock.lock();
		
		if (goodsE.getStock() < req.getBuyNum()) {
			return new WxPayUnifyOrderRES(false, null, "购买商品库存不够");
		}
		try {
			// 扣减库存
			goodsE.setStock(goodsE.getStock() - req.getBuyNum());
			goodsRepo.save(goodsE);
			cacheService.clearGoods(goodsE.getCode());
			// 生成订单号
			String orderNo = RandomUtil.genOrder("R", 16);
			tradeOrder.setOrderNo(orderNo);

		} catch (Exception e) {
			e.printStackTrace();
			return new WxPayUnifyOrderRES(false, null, "库存处理异常");
		} finally {
			lock.unlock();
		}

		// 统一微信支付下单
		WxpayOrderReq wxpayOrderReq = new WxpayOrderReq();
		wxpayOrderReq.setSpbillCreateIp(req.getOrderIp());
		wxpayOrderReq.setBody("铅笔岛-购买" + goodsE.getName());
		wxpayOrderReq.setOutTradeNo(tradeOrder.getOrderNo());
		BigDecimal totalPrice = goodsE.getPrice().multiply(new BigDecimal(req.getBuyNum()));
		wxpayOrderReq.setTotalFee(totalPrice.multiply(G.bd(100)).intValue());
		wxpayOrderReq.setTradeType(req.getTradeType());
		wxpayOrderReq.setOpenId(req.getOpenId());
		wxpayOrderReq.setNotifyUrl(appConfig.getAppServer() + "/app/wxpay/callback/notify");
		WxpaySubmitReq resp = null;
		try {
			resp = wxpayService.order(wxpayOrderReq);
		} catch (Exception e) {
			e.printStackTrace();
			return new WxPayUnifyOrderRES(false, null, "微信支付统一下单失败");
		}
		WxPayUnifyOrderRES wxPayUnifyOrderRes = new WxPayUnifyOrderRES(true, null, "OK");

		if (resp != null) {
			// 生成订单
			tradeOrder.setOpenId(req.getOpenId());
			try {
				tradeOrder.setNickName(URLEncoder.encode(req.getNickName(), "UTF-8"));
			} catch (UnsupportedEncodingException e1) {
				e1.printStackTrace();
			}
			tradeOrder.setGoodsId(goodsE.getId());
			tradeOrder.setOrderPrice(totalPrice);
			tradeOrder.setTotalPrice(totalPrice);
			tradeOrder.setUnitPrice(goodsE.getPrice());
			tradeOrder.setPayStatus(OrderConstant.PAY_STATUS_0);
			tradeOrder.setStatus(OrderConstant.STATUS_0);
			tradeOrder.setPayWay(OrderConstant.PAY_WAY_WX);
			tradeOrder.setPrepayId(resp.getPrepayId());
			tradeOrder.setTradeNum(req.getBuyNum());
			tradeOrder.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
			tradeOrderRepo.save(tradeOrder);
			// 订单地址信息
			OrderAddressEntity address = new OrderAddressEntity();
			address.setOrderNo(tradeOrder.getOrderNo());
			address.setCityName(req.getCityName());
			address.setCountyName(req.getCountyName());
			address.setDetailInfo(req.getDetailInfo());
			address.setNationalCode(req.getNationalCode());
			address.setPostalCode(req.getPostalCode());
			address.setProvinceName(req.getProvinceName());
			address.setTelNumber(req.getTelNumber());
			address.setUserName(req.getUserName());
			address.setOpenId(req.getOpenId());
			address.setOrderTime(tradeOrder.getCreateTime());
			orderAddressRepo.save(address);
			
			//维护用户收货信息
			saveUserAddress(address);
			
			//同步订单信息到mgt
			syncOrderToMgt(goodsE, tradeOrder, address);

			try {
				BeanUtils.copyProperties(wxPayUnifyOrderRes, resp);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			wxPayUnifyOrderRes.setOrderNo(tradeOrder.getOrderNo());
		}

		return wxPayUnifyOrderRes;
	}
	
	@Async
	private void saveUserAddress(OrderAddressEntity address){
		StringBuilder addressSource = new StringBuilder();
		addressSource.append("userName=")
					 .append(address.getUserName())
					 .append("&telNumber=")
					 .append(address.getTelNumber())
					 .append("&provinceName=")
					 .append(address.getProvinceName())
					 .append("&cityName=")
					 .append(address.getCityName())
					 .append("&countyName=")
					 .append(address.getCountyName())
					 .append("&detailInfo=")
					 .append(address.getDetailInfo());
		String md5 = new Md5Hash(addressSource.toString()).toHex();
		UserAddressEntity userAddress = userAddressRepo.findByOpenIdAndMd5(address.getOpenId(),md5);
		if(userAddress==null){
			log.info("存放用户【{}】新地址【{}】",address.getOpenId(),md5);
			userAddress=new UserAddressEntity();
			try {
				BeanUtils.copyProperties(userAddress, address);
			} catch (Exception e) {
				e.printStackTrace();
			}
			userAddress.setMd5(md5);
			userAddress.setCreateTime(address.getOrderTime());
			userAddressRepo.save(userAddress);
		}
		
	}

	@Async
	private void syncOrderToMgt(GoodsEntity goodsE, TradeOrderEntity tradeOrder, OrderAddressEntity address) {
		SyncOrderREQ syncOrder = new SyncOrderREQ();
		try {
			BeanUtils.copyProperties(syncOrder, tradeOrder);
			BeanUtils.copyProperties(syncOrder, address);
		} catch (Exception e) {
			e.printStackTrace();
		} 
		syncOrder.setGoodsCode(goodsE.getCode());
		syncOrder.setType("prepay");
		
		SyncOrderRES syncOrderRes = restService.sendToMgtMP("syncOrder", syncOrder, SyncOrderRES.class);
		if(syncOrderRes.getSuccess()){
			tradeOrder.setSyncMgt("1");
			tradeOrderRepo.save(tradeOrder);
		}
	}

}
